

//////////////////////////////////////////////////////////////////////////////

#ifndef AC_TLM_ROT_H_
#define AC_TLM_ROT_H_

//////////////////////////////////////////////////////////////////////////////

// Standard includes
// SystemC includes
#include <systemc>
// ArchC includes
#include "ac_tlm_protocol.H"
#include "ac_tlm_port.H"

//////////////////////////////////////////////////////////////////////////////

// using statements
using tlm::tlm_transport_if;

//////////////////////////////////////////////////////////////////////////////

//#define DEBUG

/// Namespace to isolate memory from ArchC
namespace user
{

/// A TLM router
class ac_tlm_rot :
  public sc_module,
  public ac_tlm_transport_if // Using ArchC TLM protocol
{
public:
  ac_tlm_port mem_port;
  ac_tlm_port mul_port;
  ac_tlm_port add_port;
  ac_tlm_port exp_port;
  ac_tlm_port srt_port;
  ac_tlm_port div_port;
  ac_tlm_port lck_port;
  
  /// Exposed port with ArchC interface
  sc_export< ac_tlm_transport_if > target_export;
  sc_export< ac_tlm_transport_if > target_export2;
  sc_export< ac_tlm_transport_if > target_export3;
  

  //Handle endianess
  uint32_t changeEndianess(uint32_t);
  
  /**
   * Implementation of TLM transport method that
   * handle packets of the protocol doing apropriate actions.
   * This method must be implemented (required by SystemC TLM).
   * @param request is a received request packet
   * @return A response packet to be send
  */
  ac_tlm_rsp transport( const ac_tlm_req &request ) {

    ac_tlm_rsp response;
    ac_tlm_rsp new_response;
    ac_tlm_req new_request;

    if(request.addr<5242880){
      response = mem_port->transport(request);

    }else{
      if(request.type == WRITE) {
        new_request.data = changeEndianess(request.data);
        new_request.type = WRITE;
        new_request.addr = request.addr - (4 - 2*(request.addr%8));
      }
      else{
        new_request.addr = request.addr - (4 - 2*(request.addr%8));
        new_request.type = READ;
      }

      if(request.addr == 5242880 ){
        response = lck_port->transport(new_request);
      }
      else if(request.addr >= 5242884 && request.addr <  5242932){
        response = mul_port->transport(new_request);
      }
      else if(request.addr >= 5242932 && request.addr <  5242980){
        response = add_port->transport(new_request);	
      }
      else if(request.addr >= 5242980 && request.addr <  5243028){
        response = div_port->transport(new_request);
      }
      else if(request.addr >= 5243028 && request.addr <  5243052){
       	response = exp_port->transport(new_request);
      }
      else if(request.addr >= 5243052 && request.addr <  5243068){
        response = srt_port->transport(new_request);
      }

      if(request.type == READ) {
        new_response.data = changeEndianess(response.data);
        new_response.status = SUCCESS;
	      return new_response;
      }

    }
 
    return response;
  }
 
  /**
   * Default constructor.
   *
   */
  ac_tlm_rot( sc_module_name module_name);

  /**
   * Default destructor.
   */
  ~ac_tlm_rot();
private:

};

};

#endif //AC_TLM_ROT_H_
